﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Net;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
using System.Diagnostics;
using Shoozla.DataModel.Helper;

namespace Shoozla.DataModel
{
    
    //it is a cache
    public class InternetCoverStorage : ICoverStorage
    {
        private ConcurrentDictionary<String,Image> _covers;
        private ParallelOptions _paralleSettings;
        public CancellationToken CancelToken
        {
            get { return _paralleSettings.CancellationToken; }
            set { _paralleSettings.CancellationToken = value; }
        }

        public event ImageDownloadedDelegate ImageDownloaded;
        public delegate void ImageDownloadedDelegate(Image image);

        public bool RemoveCover(string uri)
        { 
            Image oldValue;
            return _covers.TryRemove(uri.ToLowerInvariant(), out oldValue);
        }

        public InternetCoverStorage(CancellationToken token)
        {
            _covers = new ConcurrentDictionary<String,Image>();
            _paralleSettings = new ParallelOptions();
            CancelToken = token;
        }

        private void DownloadImageFromInternet(KeyValuePair<string, Image> item)
        {
          _covers.AddOrUpdate(item.Key, (key) => DownloadImage(key), (key, oldValue) => DownloadImage(key));
        }

        private Image DownloadImage(string uri)
        {
            try
            {
                WebRequest req = WebRequest.Create(uri);
                WebResponse response = req.GetResponse();
                Stream stream = response.GetResponseStream();
                Image im = Image.FromStream(stream);
                Trace.WriteLine("[IMAGE] Download Image: " + uri);
                if (ImageDownloaded != null)
                {
                    foreach (Delegate d in ImageDownloaded.GetInvocationList())
                    {
                        d.DynamicInvoke(im); //updating the UI
                    }
                }
                        
                return im;

            }
            catch (Exception e)
            {
                Trace.WriteLine("[ERROR] InternetCoverStorage: DownloadImage: " + e.Message);
                return null;
            }
        }

        public bool ContainsCover(string uri) {
            return _covers.ContainsKey(uri.ToLowerInvariant());
        }

        public Image this[string uri]
        {
            get
            { return _covers[uri.ToLowerInvariant()]; }
        }

        /// <summary>
        /// synchronous download of all images
        /// </summary>
        public void DownloadImages()
        {
            Task backgroundDownloadTask = Task.Factory.StartNew(() =>
                       {                          
                           _paralleSettings.MaxDegreeOfParallelism = ThreadHelper.CalculateTreads(_covers.Count, ThreadingFactorEnum.Maximum);
                           Parallel.ForEach(_covers,_paralleSettings, (item) => DownloadImageFromInternet(item));
                       }, CancelToken);

            backgroundDownloadTask.Wait(CancelToken);
        }

        public bool AddCoverToStorage(String coverUri)
        {
                lock (this)
                {
                    try
                    {
                        coverUri = coverUri.ToLowerInvariant();

                        //System.Drawing.Image dummyImage = null;
                        //_covers.AddOrUpdate(coverUri.ToLowerInvariant(), dummyImage, (x, y) => dummyImage);


                        if (!_covers.ContainsKey(coverUri))
                        {
                            _covers.GetOrAdd(coverUri, (Image)null); //override
                            //now download the image asynchronously
                            Action downloadImageAction = new Action(
                                 () =>
                                 {
                                     _covers.AddOrUpdate(coverUri, (key) => DownloadImage(coverUri), (key, oldValue) => DownloadImage(coverUri));
                                     //       _numActiveDownload--;
                                 });

                            //_numActiveDownload++;
                            //Parallel.Invoke(
                            Task downloadImageTask = Task.Factory.StartNew(downloadImageAction, CancelToken);
                            //  _tasks.Add(downloadImageTask);
                        }
                        else
                        {
                            //cover already downlaod, but let's trigger the event to display the UI
                            if (ImageDownloaded != null)
                            {
                                foreach (Delegate d in ImageDownloaded.GetInvocationList())
                                {
                                    d.DynamicInvoke(_covers[coverUri]); //updating the UI
                                }
                            }

                            Trace.WriteLine("[IMAGE] Cache: " + coverUri);
                        }

                        return true;
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine("[ERROR] InternetCoverStorage: AddCoverToStorage: " + e.Message);
                        return false;
                    }
                }
        }

        public void LoadFromStorage(string filename)
        {
            ; ;
        }

        public void SaveToStorage(string filename)
        {

            ; ;
        }

        public MultithreadingObservableCollection<Mp3File> GetAllCovers()
        {
            return null;
        }

        public void Reset()
        {
            _covers.Clear();
        }
    }
}
